package com.lineage.server.model;

import com.lineage.server.model.map.L1Map;
import com.lineage.server.model.map.L1WorldMap;
import com.lineage.server.types.Point;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class L1Location extends Point {
  private static final Log _log = LogFactory.getLog(L1Location.class);
  
  private static Random _random = new Random();
  
  protected L1Map _map;
  
  public L1Location() {
    this._map = L1Map.newNull();
  }
  
  public L1Location(L1Location loc) {
    this(loc._x, loc._y, loc._map);
  }
  
  public L1Location(int x, int y, int mapId) {
    super(x, y);
    this._map = L1Map.newNull();
    setMap(mapId);
  }
  
  public L1Location(int x, int y, L1Map map) {
    super(x, y);
    this._map = L1Map.newNull();
    this._map = map;
  }
  
  public L1Location(Point pt, int mapId) {
    super(pt);
    this._map = L1Map.newNull();
    setMap(mapId);
  }
  
  public L1Location(Point pt, L1Map map) {
    super(pt);
    this._map = L1Map.newNull();
    this._map = map;
  }
  
  public void set(L1Location loc) {
    this._map = loc._map;
    this._x = loc._x;
    this._y = loc._y;
  }
  
  public void set(int x, int y, int mapId) {
    set(x, y);
    setMap(mapId);
  }
  
  public void set(int x, int y, L1Map map) {
    set(x, y);
    this._map = map;
  }
  
  public void set(Point pt, int mapId) {
    set(pt);
    setMap(mapId);
  }
  
  public void set(Point pt, L1Map map) {
    set(pt);
    this._map = map;
  }
  
  public L1Map getMap() {
    return this._map;
  }
  
  public int getMapId() {
    return this._map.getId();
  }
  
  public void setMap(L1Map map) {
    this._map = map;
  }
  
  public void setMap(int mapId) {
    this._map = L1WorldMap.get().getMap((short)mapId);
  }
  
  public boolean equals(Object obj) {
    if (!(obj instanceof L1Location))
      return false; 
    L1Location loc = (L1Location)obj;
    return (getMap() == loc.getMap() && getX() == loc.getX() && getY() == loc.getY());
  }
  
  public int hashCode() {
    return 7 * this._map.getId() + hashCode();
  }
  
  public String toString() {
    return String.format("(%d, %d) on %d", new Object[] { Integer.valueOf(this._x), Integer.valueOf(this._y), 
          Integer.valueOf(this._map.getId()) });
  }
  
  public L1Location randomLocation(int max, boolean isRandomTeleport) {
    return randomLocation(0, max, isRandomTeleport);
  }
  
  public L1Location randomLocation(int min, int max, boolean isRandomTeleport) {
    return randomLocation(this, min, max, isRandomTeleport);
  }
  
  public static L1Location randomLocation(L1Location baseLocation, int min, int max, boolean isRandomTeleport) {
    L1Location newLocation = null;
    try {
      if (min > max)
        throw new IllegalArgumentException("min > max 设定异常"); 
      if (max <= 0)
        return new L1Location(baseLocation); 
      if (min < 0)
        min = 0; 
      newLocation = new L1Location();
      int newX = 0;
      int newY = 0;
      int locX = baseLocation.getX();
      int locY = baseLocation.getY();
      short mapId = (short)baseLocation.getMapId();
      L1Map map = baseLocation.getMap();
      newLocation.setMap(map);
      int locX2 = locX - max;
      int locX3 = locX + max;
      int locY2 = locY - max;
      int locY3 = locY + max;
      int mapX1 = map.getX();
      int mapX2 = mapX1 + map.getWidth();
      int mapY1 = map.getY();
      int mapY2 = mapY1 + map.getHeight();
      if (locX2 < mapX1)
        locX2 = mapX1; 
      if (locX3 > mapX2)
        locX3 = mapX2; 
      if (locY2 < mapY1)
        locY2 = mapY1; 
      if (locY3 > mapY2)
        locY3 = mapY2; 
      int diffX = locX3 - locX2;
      int diffY = locY3 - locY2;
      int trial = 0;
      int amax = (int)Math.pow((1 + max * 2), 2.0D);
      int amin = (min == 0) ? 0 : (int)Math.pow((1 + (min - 1) * 2), 2.0D);
      int trialLimit = 40 * amax / (amax - amin);
      boolean run = true;
      while (run) {
        if (trial >= trialLimit) {
          newLocation.set(locX, locY);
          run = false;
          break;
        } 
        trial++;
        try {
          newX = locX2 + _random.nextInt(diffX + 1);
          newY = locY2 + _random.nextInt(diffY + 1);
        } catch (Exception e2) {
          newLocation.set(locX, locY);
          run = false;
          break;
        } 
        newLocation.set(newX, newY);
        if (baseLocation.getTileLineDistance(newLocation) < min)
          continue; 
        if (isRandomTeleport) {
          if (L1CastleLocation.checkInAllWarArea(newX, newY, mapId))
            continue; 
          if (L1HouseLocation.isInHouse(newX, newY, mapId))
            continue; 
        } 
        if (map.isInMap(newX, newY) && map.isPassable(newX, newY, null)) {
          run = false;
          break;
        } 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
    return newLocation;
  }
}
